/*
 * @file iso9660_susp.h
 *
 *  ISO9660 System Use Sharing Protocol management
 *
 */

#include "iso9660_record.h"
#include "iso9660_types.h"

#ifndef __ISO9660_SUSP_H_
#define __ISO9660_SUSP_H_

#define ISO9660_SUSP_SIGNATURE_STR(_x)  ISO_STR(_x, 0)  /**< Signature word of an SUSP entry */
#define ISO9660_SUSP_SIGNATURE(_x)      ISO_U16(_x, 0)  /**< Signature word of an SUSP entry */
#define ISO9660_SUSP_SIZE(_x)           ISO_U8(_x, 2)   /**< Length of the entry */
#define ISO9660_SUSP_VERSION(_x)        ISO_U8(_x, 3)   /**< Entry version */
#define ISO9660_SUSP_DATA(_x)           ISO_PTR(_x, 4, void)
#define ISO9660_SUSP_DATA_OFS(_ofs)     (4 + _ofs)

/* SUSP standard entries */
#if CPU_LITTLE_ENDIAN == TRUE
#define ISO9660_SUSP_SIGNATURE_CE           0x4543  /**< 'CE' : Continuation Area */
#define ISO9660_SUSP_SIGNATURE_SP           0x5053  /**< 'SP' : Sharing Protocol */
#define ISO9660_SUSP_SIGNATURE_ST           0x5453  /**< 'ST' : Terminator */
#define ISO9660_SUSP_SIGNATURE_ER           0x5245  /**< 'ER' : Extension */
#else
#define ISO9660_SUSP_SIGNATURE_CE           0x4345  /**< 'CE' : Continuation Area */
#define ISO9660_SUSP_SIGNATURE_SP           0x5350  /**< 'SP' : Sharing Protocol */
#define ISO9660_SUSP_SIGNATURE_ST           0x5354  /**< 'ST' : Terminator */
#define ISO9660_SUSP_SIGNATURE_ER           0x4552  /**< 'ER' : Extension */
#endif

/* Rock Ridge (RRIP) SUSP entries */
#if CPU_LITTLE_ENDIAN == TRUE
#define ISO9660_SUSP_SIGNATURE_RR           0x5252  /**< 'RR' : Rock Ridge (before spec 1.09) */
#define ISO9660_SUSP_SIGNATURE_NM           0x4D4E  /**< 'NM' : Alternate name */
#define ISO9660_SUSP_SIGNATURE_PX           0x5850  /**< 'PX' : POSIX modes */
#define ISO9660_SUSP_SIGNATURE_TF           0x4654  /**< 'TF' : Timestamp(s) */
#else
#define ISO9660_SUSP_SIGNATURE_RR           0x5252  /**< 'RR' : Rock Ridge (before spec 1.09) */
#define ISO9660_SUSP_SIGNATURE_NM           0x4E4D  /**< 'NM' : Alternate name */
#define ISO9660_SUSP_SIGNATURE_PX           0x5058  /**< 'PX' : POSIX modes */
#define ISO9660_SUSP_SIGNATURE_TF           0x5446  /**< 'TF' : Timestamp(s) */
#endif

/* SP entry */
#define ISO9660_SUSP_SP_CHECK(_x)       ISO_U16(_x, ISO9660_SUSP_DATA_OFS(0))
#define ISO9660_SUSP_SP_SKIP(_x)        ISO_U8(_x, ISO9660_SUSP_DATA_OFS(2))

#if CPU_LITTLE_ENDIAN == TRUE
#define ISO9660_SUSP_SP_CHECK_VALUE     0xEFBE
#else
#define ISO9660_SUSP_SP_CHECK_VALUE     0xBEEF
#endif

/* ER entry */
#define ISO9660_SUSP_ER_ID_LEN(_x)      ISO_U8(_x, ISO9660_SUSP_DATA_OFS(0))
#define ISO9660_SUSP_ER_DESC_LEN(_x)    ISO_U8(_x, ISO9660_SUSP_DATA_OFS(1))
#define ISO9660_SUSP_ER_SOURCE_LEN(_x)  ISO_U8(_x, ISO9660_SUSP_DATA_OFS(2))
#define ISO9660_SUSP_ER_ID(_x)          ISO_STR(_x, ISO9660_SUSP_DATA_OFS(3))
#define ISO9660_SUSP_ER_DESC(_x)        ISO_STR(_x, ISO9660_SUSP_DATA_OFS(3     \
                                            + ISO9660_SUSP_ER_ID_LEN(_x)))
#define ISO9660_SUSP_ER_SOURCE(_x)      ISO_STR(_x, ISO9660_SUSP_DATA_OFS(3     \
                                            + ISO9660_SUSP_ER_ID_LEN(_x)         \
                                            + ISO9660_SUSP_ER_DESC_LEN(_x)))

/* CE entry */
#define ISO9660_SUSP_CE_LOCATION(_x)    ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(0))
#define ISO9660_SUSP_CE_OFFSET(_x)      ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(8))
#define ISO9660_SUSP_CE_LENGTH(_x)      ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(16))


/* NM entry */
#define ISO9660_SUSP_NM_FLAGS(_x)       ISO_U8(_x, ISO9660_SUSP_DATA_OFS(0))
#define ISO9660_SUSP_NM_NAME(_x)        ISO_STR(_x, ISO9660_SUSP_DATA_OFS(1))
#define ISO9660_SUSP_NM_NAME_LEN(_x)    (ISO9660_SUSP_SIZE(_x)                  \
                                            - ISO9660_SUSP_DATA_OFS(1))

#define ISO9660_SUSP_NM_FLAG_CONTINUE   (1 << 0)
#define ISO9660_SUSP_NM_FLAG_CURRENT    (1 << 1)
#define ISO9660_SUSP_NM_FLAG_PARENT     (1 << 2)


/* PX entry */
#define ISO9660_SUSP_PX_MODE(_x)        ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(0))
#define ISO9660_SUSP_PX_NLINKS(_x)      ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(8))
#define ISO9660_SUSP_PX_UID(_x)         ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(16))
#define ISO9660_SUSP_PX_GID(_x)         ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(24))
#define ISO9660_SUSP_PX_INO(_x)         ISO_BU32(_x, ISO9660_SUSP_DATA_OFS(32))


/* TF entry */
#define ISO9660_SUSP_TF_FLAGS(_x)       ISO_U8(_x, ISO9660_SUSP_DATA_OFS(0))

#define ISO9660_SUSP_TF_FLAG_CREATION   (1 << 0)
#define ISO9660_SUSP_TF_FLAG_MODIFY     (1 << 1)
#define ISO9660_SUSP_TF_FLAG_ACCESS     (1 << 2)
#define ISO9660_SUSP_TF_FLAG_ATTRIBUTE  (1 << 3)
#define ISO9660_SUSP_TF_FLAG_BACKUP     (1 << 4)
#define ISO9660_SUSP_TF_FLAG_EXPIRATION (1 << 5)
#define ISO9660_SUSP_TF_FLAG_EFFECTIVE  (1 << 6)
#define ISO9660_SUSP_TF_FLAG_LONG_FORM  (1 << 7)

typedef uint8_t iso9660_susp_entry_t;

typedef struct iso9660_susp_entry_tf_s {
  struct {
    int creation      : 1;
    int modify        : 1;
    int access        : 1;
    int attribute     : 1;
    int backup        : 1;
    int expiration    : 1;
    int effective     : 1;
    int long_form     : 1;
  }                     flags;
} iso9660_susp_entry_tf_t;



typedef struct iso9660_susp_list_s {
  void                *data;
  uint16_t             size;
  uint16_t             next_entry_offset;
  uint8_t              flags;
  iso9660_fs_info_t   *fs;
} iso9660_susp_list_t;


/* iso9660_susp_list_t flags */
#define RTEMS_ISO9660_SUSP_LIST_HEAP_DATA   (1 << 0)  /**< The data has been
                                 allocated on the heap and should be freed */

/* iso9660_susp_list_t list end indicator */
#define RTEMS_ISO9660_SUSP_LIST_END         1

int
iso9660_susp_update_fs_info(
    iso9660_fs_info_t          *fs
);

int
iso9660_susp_entry_open_dir_record(
    iso9660_directory_record_t *record,
    iso9660_fs_info_t          *fs,
    iso9660_susp_list_t        *list,
    uint8_t                     skip
);

int
iso9660_susp_entry_open_record(
    iso9660_record_t      *record,
    iso9660_susp_list_t   *list
);

int
iso9660_susp_list_init(
    iso9660_susp_list_t  *list,
    iso9660_fs_info_t    *fs,
    void                 *space,
    uint16_t              size,
    uint16_t              offset,
    uint8_t               flags
);

int
iso9660_susp_list_free(
    iso9660_susp_list_t  *list
);

int
iso9660_susp_list_next_entry(
    iso9660_susp_list_t   *list,
    iso9660_susp_entry_t **entry
);

int
iso9660_susp_list_search(
    iso9660_susp_entry_t **result,
    uint16_t               signature,
    iso9660_susp_list_t   *list
);
#endif /* __ISO9660_SUSP_H_ */
